<!-- 卡片菜单 -->
<template>
  <div class="cardMenuX">

    <!-- 菜单内容 -->
    <div class="cardMenuContent">
      <scroll-x :scroll-style="{always: true}" ref="scrollDom" v-bind="$attrs">
        <div class="cardItemBox">
          <div class="cardItem" v-for="item in props.list" :key="item[props.key]">
            <card-item-x :props="propsD" :list="props.list" ref="cardDom"
                         :margin-left="props.marginLeft" @check="checkFn"
                         :item="item" :change="props.change">
              <template #title="{data}">
                <slot name="title" :data="data">
                  <span class="menuTitle">{{ data[propsD.title] }}</span>
                </slot>
              </template>
            </card-item-x>
          </div>
        </div>
      </scroll-x>
    </div>
  </div>
</template>

<script setup>
import {ref, watch, computed} from 'vue'
import CardItemX from "./xhykCardMenuItem.vue";
import ScrollX from "../xhykScroll.vue";

const props = defineProps({
  // 是否全部已经了勾选
  modelValue: {
    type: [String, Number, Object, Boolean],
    default: false
  },

  // 菜单列表
  list: {
    type: Object,
    default: []
  },

  // 菜单字段
  props: {
    type: Object,
    default: {
      key: 'name',
      icon: 'icon',
      children: 'children',
      title: 'title',
      // 勾选字段
      checkX: 'checkX',
      // 待定字段
      awaitX: 'awaitX',
      // 禁止
      disabledX: 'disabledX',
    }
  },

  // 勾选事件。返回false时则取消勾选下层的操作
  change: {
    type: Function,
    default: async (item, toCheck) => {

    }
  },

  // 左边缩进
  marginLeft: {
    type: [String, Number],
    default: "24px"
  },

  // 是否不是全部勾选，但存在勾选数据
  haveCheck: {
    type: Boolean,
    default: false
  },
})

const emit = defineEmits(['check', 'update:modelValue', 'update:haveCheck'])

// 配置信息
const propsD = computed(() => {
  let result = {
    key: props.props.name || 'name',
    icon: props.props.icon || 'icon',
    children: props.props.children || 'children',
    title: props.props.title || 'title',
    // 禁止
    disabledX: props.props.disabledX || 'disabledX',
    // 勾选字段
    checkX: props.props.checkX || 'checkX',
    // 待定字段
    awaitX: props.props.awaitX || 'awaitX'
  }
  return result
})

// 勾选事件
const checkFn = ({item, toCheck}) => {
  emit("check", {
    item: item,
    toCheck: toCheck
  })
}


// 遍历嵌套取对象。根据children字段遍历下级列表。返回当前子级对象
async function findChildren(data = [], callBack = undefined, children = "children") {
  let tempResult = undefined
  const findFn = async (ChildData, father) => {
    let isOk = false
    for (let item of ChildData) {
      if (typeof callBack == "function") {
        const isBreak = await callBack(item, father)
        if (isBreak == true) {
          tempResult = item
          isOk = true
          break;
        }
      }
      if (isOk) {
        tempResult = item
        return item
      }

      // 如果有下一级数据
      if (item[children] != undefined && item[children].length > 0) {
        let result = await findFn(item[children], item)
        if (result) {
          return true
        }
      }
    }
    return isOk;
  }
  await findFn(data, {})
  return tempResult
}

/* 组件方法 */
const cardDom = ref({})
// 全选触发事件，不触发事件
const eventFn = (child, toCheck) => {
  if (cardDom.value instanceof Array && cardDom.value.length > 0) {
    cardDom.value[0].toCheckFn(child, toCheck, false)
  } else if (cardDom.value.toCheckFn) {
    cardDom.value.toCheckFn(child, toCheck, false)
  }
}

const toCheckFn = async (row, toCheck) => {
  findChildren(props.list, (child) => {
    if (row[propsD.value.key] == child[propsD.value.key]) {
      // 触发勾选事件
      eventFn(child, toCheck)
      return true
    }
  }, propsD.value.children)
}


// 监听全选状态
const changeAll = (newV) => {
  if (newV) {
    // 真时，去勾选全部父级
    props.list.forEach(item => toCheckFn(item, newV))
  } else {
    // 假
    findChildren(props.list, (child) => {
      eventFn(child, false)
    }, propsD.value.children)
  }
}


// 改变标识
watch(() => props.list, async newV => {
  // 是否显示等待状态。不为undefined时表示存在勾选对象
  let haveCheck = undefined

  // 是否全选
  let isAll = true
  await findChildren(newV, (child) => {
    if (child[propsD.value.checkX] != true) {
      // 有一个不是被勾选的，就不是全部都被勾选
      isAll = false
    }
    if (child[propsD.value.checkX] == true && haveCheck == undefined) {
      haveCheck = true
    }
  }, propsD.value.children)

  // 改变等待标识。没有全部勾选。又存在选中数据
  haveCheck = (haveCheck == true && isAll == false)?true:false
  emit("update:haveCheck", haveCheck)

  // 改变全选标识
  emit("update:modelValue", isAll)
}, {immediate: true,deep: true})


/* 滚动条组件 */
const scrollDom = ref({})


defineExpose({
  // 关闭状态需要调用方法
  toCheckFn,
  changeAll,
  scrollDom
})

</script>

<style scoped lang='scss'>
.cardMenuX {
  width: 100%;
  height: 100%;
  position: relative;

  .cardMenuContent {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;

    .cardItemBox {
      height: 100%;
      margin: 0px 14px;
    }
  }
}

.cardItem {
  flex: 1 1 auto;
  width: 100%;
}
</style>